package org.codefinger.dao.impl.mysql;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.codefinger.dao.impl.DataAccesser;
import org.codefinger.dao.impl.QueryBuilder;
import org.codefinger.dao.impl.TableInfo;
import org.codefinger.dao.impl.sql.UValueItem;
import org.codefinger.dao.util.Lang;
import org.codefinger.dao.util.jdbc.JDBCUtil;

public class MySQLDataAccesser extends DataAccesser {

	public MySQLDataAccesser(DataSource dataSource) {
		super(dataSource);
	}

	@Override
	protected QueryBuilder createQueryBuilder() {
		return new MySQLQueryBuilder(this);
	}

	@Override
	protected TableInfo createTableInfo(String table) {
		table = table.toUpperCase();
		Connection connection = null;
		ResultSet resultSet = null;
		PreparedStatement statement = null;
		try {
			connection = getDataSource().getConnection();
			DatabaseMetaData databaseMetaData = connection.getMetaData();

			resultSet = databaseMetaData.getTables(//
					null, "%", table, new String[] { "TABLE" });

			String tableCat;
			if (resultSet.next()) {
				tableCat = resultSet.getString("TABLE_CAT");
				resultSet.close();
			} else {
				throw Lang.makeThrow("Can not find the table named '%s'.", table);
			}

			statement = connection.prepareStatement(//
					"SELECT COLUMN_NAME, COLUMN_KEY, EXTRA, COLUMN_TYPE FROM INFORMATION_SCHEMA.`COLUMNS` WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?");
			statement.setString(1, tableCat);
			statement.setString(2, table);

			resultSet = statement.executeQuery();
			String primaryKey = null;
			List<String> columns = new ArrayList<String>();

			StringBuilder insertSQLBuilder = new StringBuilder("INSERT INTO ").append(table).append("(");
			boolean flag = false;

			while (resultSet.next()) {
				String columnName = resultSet.getString(1).toUpperCase();
				columns.add(columnName);
				if ("PRI".equals(resultSet.getString(2)) && primaryKey == null) {
					if (resultSet.getString(3).toLowerCase().indexOf("auto_increment") < 0) {
						Statement uStatement = connection.createStatement();
						uStatement.execute(Lang.joinString("ALTER TABLE ", table, " MODIFY COLUMN ", columnName, " ", resultSet.getString(4), " NOT NULL AUTO_INCREMENT FIRST").toString());
						uStatement.close();
					}
					primaryKey = columnName;
					continue;
				}
				if (flag) {
					insertSQLBuilder.append(',').append(columnName);
				} else {
					insertSQLBuilder.append(columnName);
					flag = true;
				}
			}

			if (primaryKey == null) {
				throw Lang.makeThrow(//
						"Can not find the primary key from the table '%s'.", table);
			}

			insertSQLBuilder.append(") VALUES (?");
			int size = columns.size();
			int count = size - 1;
			for (int i = 1; i < count; i++) {
				insertSQLBuilder.append(",?");
			}

			return new TableInfo(table, primaryKey, columns.toArray(new String[size]), insertSQLBuilder.append(')').toString());
		} catch (SQLException e) {
			throw Lang.wrapThrow(//
					e, "Matched an error during find infomation from the table '%s'.", table);
		} finally {
			JDBCUtil.freeResource(connection, statement, resultSet);
		}
	}

	@Override
	protected QueryBuilder createWhereBuilder() {
		return new MySQLQueryBuilder();
	}

	@Override
	protected QueryBuilder createUValueBuilder() {
		return new MySQLQueryBuilder(new ArrayList<UValueItem>());
	}

	@Override
	protected QueryBuilder createIValueBuilder(String table) {
		return new MySQLQueryBuilder(this, table);
	}

}
